package battleships;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import com.google.gson.Gson;

/*
 * Handler class - redirects most game-related stuff where they need to go
 */
public class Handler {
	private static final HashMap<Integer, User> users = new HashMap<Integer, User>();
	private static final HashMap<Integer, Game> games = new HashMap<Integer, Game>();
	private static final HashMap<Integer, Integer> usersGame = new HashMap<Integer, Integer>();
	private static Integer userCount = 0, gameCount = 0;
	
	static Integer addUser() {
		User u = new User(userCount);
		users.put(userCount, u);
		userCount++;
		//Chat.addMessageToAll("update");
		//Chat.addListUpdateToAll();	
		return u.getUserId();
	}
	
	static void removeGame(Integer gameId, Integer winner) {
		System.err.println("=== Removing game " + gameId);
		Game g = games.get(gameId);
		usersGame.remove(g.p1);
		usersGame.remove(g.p2);
		users.get(g.p1).setAvailable(true);
		users.get(g.p2).setAvailable(true);
		//Statistics
		users.get(g.p1).addGameEnd(g.p1 == winner);
		users.get(g.p2).addGameEnd(g.p2 == winner);
		
		games.remove(gameId);
		
		Chat.addMessageToAll("update");
		Chat.addListUpdateToAll();
	}
	
	static void addGame(Integer p1, Integer p2) {
		System.err.println("Starting game between " + p1 + " and " + p2);
		games.put(gameCount, new Game(p1, p2));
		usersGame.put(p1, gameCount);
		usersGame.put(p2, gameCount);
		users.get(p1).setAvailable(false);
		users.get(p2).setAvailable(false);
		gameCount++;
		Chat.addMessageToAll("update");
		Chat.addListUpdateToAll();
	}
	
	/* p1 challenges p2 */
	static String challenge(Integer p1, Integer p2) {
		System.err.println(p1 + "(" + users.get(p1).getName()+") challenges " + p2 + "(" + users.get(p2).getName()+")");
		// Both players should be available
		if (!users.get(p1).isAvailable() || !users.get(p2).isAvailable()) {
			System.err.println("Someone isn't available!");
			return "";
		}
		// Set challenger unavailable, so he wouldn't get challenged
		users.get(p1).setAvailable(false);
		users.get(p2).setAvailable(false);
		users.get(p1).setChallenging(p2);
		users.get(p2).setChallenge(p1);
		
		System.err.println(p1 + "(" + users.get(p1).getName()+") challenges " + p2 + "(" + users.get(p2).getName()+")");
		
		Chat.addMessage(p2, "challenge&" + p1 + "&" + users.get(p1).getName());
		Chat.addMessageToAll("update");
		Chat.addListUpdateToAll();
		//Wait for response for a while
		String msg = users.get(p1).getMessage(30);
		System.err.println(new Date() + ": " + p1 + ", "+ msg);
		Chat.addMessageToAll("update");
		// no response - end it
		if (msg.equals(""))
			msg = "decline";
		if (msg.equals("decline")) {
			users.get(p1).setChallenging(null);
			users.get(p2).setChallenge(null);
			users.get(p1).setAvailable(true);
			users.get(p2).setAvailable(true);
			Chat.addListUpdateToAll();
		}
		if (msg.equals("accept")) 
			users.get(p1).clearMessages();
		return msg;
	}
	
	static String challengeAnswer(Integer p1, String ans) {
		Integer p2 = users.get(p1).getChallenger();
		// Challenge was aborted
		if (p2 == null) 
			return "decline";
		if (users.get(p2).getChallenging() != p1) 
			return "decline";
		// send message to challenge and create new game
		System.err.println(p1+" "+ans+" opponent "+p2+" challenge");
		users.get(p2).putMessage(ans);
		if (ans.equals("accept")) {
			addGame(p1, p2);
			users.get(p1).clearMessages();
		}
		return ans;
	}
	
	/* Servlet -> handleparams. Takes care of user request, gives back what to respond 
	 * Mostly delegates its work to other functions.
	 */
	static String handleParams(Integer userId, Map<String, String[]> params) {
		//Remove this part later
		//if (games.size() == 0) addGame(0, 1);
		
		if (params.containsKey("action")) {
			String action = params.get("action")[0];
			// UserName index page
			if (action.equals("hasUsername")) {
				return users.get(userId).getName().equals("undefined"+userId) ? "0":"1";
			}
			if (action.equals("setUsername")) {
				users.get(userId).setName(params.get("name")[0]);
				Chat.addMessageToAll("update");
				Chat.addListUpdateToAll();
				return userId + " changed name to " + params.get("name")[0];
			}
			// new game page
			if (action.equals("getWholeUserList")) {
				return getWholeUserList(userId);
			}
			if (action.equals("challenge")) {
				System.err.println("======="+params.get("id")[0]);
				Integer otherId = Integer.parseInt(params.get("id")[0]);
				return challenge(userId, otherId);
			}
			if (action.equals("challengeAnswer")) {
				return challengeAnswer(userId, params.get("answer")[0]);
			}
			// game page
			if (action.equals("place")) {
				Integer gameId = usersGame.get(userId);
				return games.get(gameId).setPlacement(userId, params.get("placement")[0]);
			}
			if (action.equals("bomb")) {
				Integer gameId = usersGame.get(userId);
				int x = Integer.parseInt(params.get("x")[0]);
				int y = Integer.parseInt(params.get("y")[0]);
				return games.get(gameId).bomb(userId, x, y);
			}
			if (action.equals("waitMove")) {
				Integer gameId = usersGame.get(userId);
				String msg = games.get(gameId).getBomb(userId);
				//Game over?
				Integer winner = games.get(gameId).winner();
				//TODO: Do some DB handling, increase win count
				if (winner != null) {
					removeGame(gameId, winner);
				}
				return msg;
			}
			// Debugging purposes for now
			if (action.equals("gameStatus")) {
				if (usersGame.containsKey(userId)) {
					Integer gameId = usersGame.get(userId);
					return games.get(gameId).getStatus(userId);
				}
			}
		}
		return "";
	}

	/* Function to return a JSON object of users */
	static String getWholeUserList(Integer ignore) {
		ArrayList<HashMap<String, String>> result = new ArrayList<HashMap<String, String>>();
		for (User u : users.values()) {
			if (u.getName().equals("undefined" + u.getUserId()))
				continue;
			HashMap<String, String> user = new HashMap<String, String>();
			user.put("id", u.getUserId().toString());
			user.put("available", (u.isAvailable() && ignore != u.getUserId()) ? "true" : "false");
			user.put("name", u.getName());
			user.put("wins", u.getWins().toString());
			user.put("games", u.getTotal().toString());
			result.add(user);
		}
		Gson gson = new Gson();
		return gson.toJson(result);
	}
	
	static String getWholeGameList() {
		ArrayList<HashMap<String, String>> result = new ArrayList<HashMap<String, String>>();
		for (Game g : games.values()) {
			HashMap<String, String> game = new HashMap<String, String>();
			game.put("p1_id", 	users.get(g.p1).getUserId().toString());
			game.put("p1_name", users.get(g.p1).getName().toString());
			game.put("p2_id", 	users.get(g.p2).getUserId().toString());
			game.put("p2_name", users.get(g.p2).getName().toString());			
			result.add(game);
		}
		Gson gson = new Gson();
		return gson.toJson(result);
	}
	
	static String getUserName(Integer userId) {
		return users.get(userId).getName();
	}
}
